﻿using System.Collections.Generic;
using UnityEngine;

[RequireComponent(typeof(UIGrid))]
public class MyLoopScroll : MonoBehaviour
{
    [SerializeField]
    GameObject ItemPrefab;
    UIScrollView scroll;

    private UIGrid grid;
    private UIPanel panel;
    private Vector4 posParam;

    private int sceneCount;
    private int dataCount;
    /// <summary>
    ///当前列表Item总数 
    /// </summary>
    private int maxItemNum;
    /// <summary>
    /// 起始下标
    /// </summary>
    private int startIndex;
    /// <summary>
    /// 列表布局有几行或者几列 
    /// </summary>
    private int maxPer;
    /// </summary>
    /// 当前页要显示的对象上表
    /// <summary>
    public int TopIndex;

    /// <summary>
    /// 物件刷新代理事件
    /// </summary>
    public ItemCallBack OnItemChange;
    /// <summary>
    /// Item点击代理事件
    /// </summary>
    public ItemCallBack OnItemClick;

    /// <summary>
    /// 存储物件列表
    /// </summary>
    List<UIWidget> mItemList = new List<UIWidget>();

    void Awake()
    {
        scroll = GetComponentInParent<UIScrollView>();
        panel = scroll.GetComponent<UIPanel>();
        grid = GetComponent<UIGrid>();

        bool horizontal = scroll.canMoveHorizontally;
        float num; maxPer = grid.maxPerLine;
        if (maxPer <= 0) { maxPer = 1; }
        
        if (horizontal)
        {
            num = panel.width / grid.cellWidth;
        }
        else
        {
            num = panel.height / grid.cellHeight;
        }

        sceneCount = Mathf.FloorToInt(num) * maxPer;
        maxItemNum = (Mathf.FloorToInt(num) + 2) * maxPer;
        panel.cullWhileDragging = true;     //设置Cull

        posParam = new Vector4(grid.cellWidth, grid.cellHeight, 
            horizontal ? 1 : 0, !horizontal ? 1 : 0);
        if (ItemPrefab != null) { InitData(); }
    }

    /// <summary>
    /// 初始化数据
    /// </summary>
    void InitData()
    {
        if (ItemPrefab)
        {
            transform.AddChildren(ItemPrefab, maxItemNum);
        }
        gameObject.GetComponentsInChildren(true, mItemList);
        for (int i = 0; i < mItemList.Count; i++)
        {
            UIEventListener.Get(mItemList[i].gameObject).onClick = OnClickItem;
            mItemList[i].autoResizeBoxCollider = true;
        }
        dataCount = maxItemNum; ResetPosition();
        Utility.SetActive(ItemPrefab, false);
    }

    void LateUpdate()
    {
        if (mItemList.Count < 1) { return; }
        int endIdx = mItemList.Count - 1;
        bool firstVislable = mItemList[0].isVisible;
        bool lastVisiable = mItemList[endIdx].isVisible;

        // 如果都显示,那么返回
        if (firstVislable == lastVisiable) { return; }
        int sourceIndex = -1, targetIndex = -1, sign = 0;

        // 得到需要替换的源和目标
        if (firstVislable)
        {
            sourceIndex = endIdx;
            targetIndex = 0;
            sign = 1;
        }
        else if (lastVisiable)
        {
            sourceIndex = 0;
            targetIndex = endIdx;
            sign = -1;
        }

        // 如果小于真正的初始索引或大于真正的结束索引,返回
        int realSourceIndex = int.Parse(mItemList[sourceIndex].name);
        int realTargetIndex = int.Parse(mItemList[targetIndex].name);
        if (realTargetIndex <= startIndex || realTargetIndex >= (dataCount - 1))
        {
            scroll.restrictWithinPanel = true;
            return;
        }

        scroll.restrictWithinPanel = false;
        UIWidget movedWidget = mItemList[sourceIndex];
        float x = sign * posParam.x * posParam.z;
        float y = sign * posParam.y * posParam.w;

        Vector3 pos = mItemList[targetIndex].cachedTransform.localPosition;
        movedWidget.cachedTransform.localPosition = pos + new Vector3(x, y, 0);

        mItemList.RemoveAt(sourceIndex);
        mItemList.Insert(targetIndex, movedWidget);

        int idx = realTargetIndex + 1;
        if (realSourceIndex > realTargetIndex)
        {
            idx = realTargetIndex - 1;
        }
        movedWidget.name = idx.ToString();
        OnChangeItem(movedWidget.gameObject, idx);
    }
    
    /// <summary>
    /// 更新表单
    /// </summary>
    /// <param name ="count">数量</param>
    public void UpdateItem(int count)
    {
        startIndex = 0; dataCount = count;
        for (int i = 0; i < mItemList.Count; i++)
        {
            mItemList[i].name = i.ToString();
            Utility.SetActive(mItemList[i], i < dataCount);

            if (i < dataCount)
            {
                mItemList[i].Invalidate(true);
                OnChangeItem(mItemList[i].gameObject, i);
            }
        }
        Utility.SetBehaviour<UIDragScrollView>(transform, sceneCount <= dataCount);
    }
    
    /// <summary>
    /// 更新表单(置顶索引)
    /// </summary>
    /// <param name="topIdx">当前显示的起始索引</param>
    public void SetItemTop(int topIdx)
    {
        int endIdx = dataCount - 1 - sceneCount;
        if (TopIndex != topIdx) { TopIndex = topIdx; }
        if (TopIndex > endIdx) { TopIndex = endIdx; }
        if (TopIndex < 0) { TopIndex = 0; }

        int num = Mathf.FloorToInt(TopIndex / maxPer);
        for (int i = 0; i < mItemList.Count; i++)
        {
            UIWidget uI = mItemList[i];
            int startIdx = num * maxPer + i;
            uI.name = startIdx.ToString();

            if (startIdx < dataCount)
            {
                uI.Invalidate(true);
                OnChangeItem(uI.gameObject, i);
            }
        }
    }
    
    /// <summary>
    /// 更新数据
    /// </summary>
    /// <param name="t"></param>
    /// <param name="idx"></param>
    void UpdateItem(Transform t, int idx)
    {
        bool bShow = idx >= 0 && idx < dataCount;
        Utility.SetActive(t, bShow);
        if (bShow)
        {
            OnChangeItem(t.gameObject, idx);
        }
    }
    
    /// <summary>
    /// 设置代理
    /// </summary>
    /// <param name="onItemChange"></param>
    /// <param name="onItemClick"></param>
    public void SetDelegate(ItemCallBack onItemChange, ItemCallBack onItemClick)
    {
        OnItemChange = onItemChange;
        OnItemClick = onItemClick;
    }

    /// <summary>
    /// 循环列表改变回调
    /// </summary>
    /// <param name="go"></param>
    /// <param name="idx"></param>
    void OnChangeItem(GameObject go, int idx)
    {
        if (OnItemChange != null)
        {
            OnItemChange(go, idx);
        }
    }

    /// <summary>
    /// 循环列表点击回调
    /// </summary>
    /// <param name="go"></param>
    void OnClickItem(GameObject go)
    {
        int idx = int.Parse(go.name);
        if (OnItemClick != null)
        {
            OnItemClick(go, idx);
        }
    }

    /// <summary>
    /// 重置循环列表位置
    /// </summary>
    void ResetPosition()
    {
        grid.Reposition();
        scroll.ResetPosition();
    }
}